package com.carter.springframework.beans.factory.support;

import com.carter.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.carter.springframework.beans.factory.config.BeanDefinition;
import com.carter.springframework.beans.exception.BeanException;
import com.carter.springframework.beans.factory.config.BeanPostProcessor;
import com.carter.springframework.beans.factory.config.CarterBeanDefinition;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ConfigurableListableBeanFactory {
    private final Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();

    private final Map<String, CarterBeanDefinition> carterBeanDefinitionMap = new HashMap<>();

    public DefaultListableBeanFactory(Class<? extends InstantiationStrategy> clazz){
        super(clazz);
    }

    public DefaultListableBeanFactory() {
        this(SimpleInstantiationStrategy.class);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws BeanException {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition!=null){
            throw new BeanException("没有名称为"+beanName+"的bean定义");
        }
        return beanDefinition;
    }

    public CarterBeanDefinition getCarterBeanDefinition(String beanName) throws BeanException{
        CarterBeanDefinition carterBeanDefinition = carterBeanDefinitionMap.get(beanName);
        if (carterBeanDefinition!=null){
            throw new BeanException("没有名称为"+beanName+"的bean定义");
        }
        return carterBeanDefinition;
    }

    @Override
    public void preInstantiateSingletons() throws BeanException {
        //beanDefinitionMap.keySet().forEach(this::getBean);
        beanDefinitionMap.entrySet().stream().filter(entry->entry.getValue().isSingleton()).forEach(entry->this.getBean(entry.getKey()));
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName,beanDefinition);
    }

    @Override
    public void registerBeanDefinition(String beanName, CarterBeanDefinition beanDefinition) {
        carterBeanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return beanDefinitionMap.containsKey(beanName);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeanException {
        Map<String, T> resultMap = new HashMap<>();
        beanDefinitionMap.forEach((beanName,beanDefinition)->{
            if (type.isAssignableFrom(beanDefinition.getBeanClass())){
                resultMap.put(beanName,getBean(beanName,type));
            }
        });
        return resultMap;
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return new String[0];
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeanException{
        List<Map.Entry<String, BeanDefinition>> filteredDefinition = beanDefinitionMap.entrySet().stream().filter(x -> requiredType.isAssignableFrom(x.getValue().getBeanClass())).collect(Collectors.toList());
        if (filteredDefinition.size()==1){
            return getBean(filteredDefinition.get(0).getKey(),requiredType);
        }
        throw new BeanException(requiredType + "expect 1 single bean but found " + filteredDefinition.size() + " "
                + filteredDefinition.stream().map(Map.Entry::getKey).collect(Collectors.toList()));
    }
}
